The need for increased software application portability (i.e., the ability to execute a given software application on a variety of platforms having different hardware, operating systems, etc.), as well as the need to reduce time to market for independent software vendors (ISVs), have resulted in increased development and usage of managed runtime environments and virtual machines.
Virtual machines (VMs) are typically implemented using a dynamic programming language such as, for example, Java™ and C#. A software engine (e.g., a Java Virtual Machine (JVM) and Microsoft®.NET Common Language Runtime (CLR), etc.), which is commonly referred to as a runtime environment, executes the dynamic program language instructions of the managed application. The VM interfaces dynamic program language instructions (e.g., a Java program or source code) to be executed to a target platform (i.e., the hardware and operating system(s) of the computer executing the dynamic program) so that the dynamic program can be executed in a platform independent manner.
Dynamic program language instructions (e.g., Java™ instructions) are not statically compiled and linked directly into native or machine code for execution by the target platform (i.e., the operating system and hardware of the target processing system or platform). Native code or machine code is code that is compiled down to methods or instructions that are specific to the operating system and/or processor. In contrast, dynamic program language instructions are statically compiled into an intermediate language (e.g., bytecodes), which may be interpreted or subsequently compiled by a just-in-time (JIT) compiler into native or machine code that can be executed by the target processing system or platform. Typically, the JIT compiler is provided by the VM that is hosted by the operating system of a target processing platform such as, for example, a computer system. Thus, the VM and, in particular, the JIT compiler, translates platform independent program instructions (e.g., Java™ bytecodes, Common Intermediate Language (CIL), etc.) into native code (i.e., machine code that can be executed by an underlying target processing system or platform).
VMs typically include interfaces (e.g., Java™ Native Interface (JNI)) to native libraries, which may be applications and/or libraries of procedures written in native programming languages (e.g., C, C++, assembly, etc.) that operate on or with the target platform. Interfacing with native libraries enables a managed application developer to call or utilize libraries that are already written, interface the managed application with hardware drivers written in native languages, and perform procedures that are not supported by the managed programming language.
A drawback to using native libraries from inside a VM is that the native libraries, unlike managed applications, are not platform-independent, unlike managed applications. Software applications written in native languages are linked directly into the native code of the platform on which they are compiled. In other words, the native libraries are not translated into the native instructions of the platform on which they are executing. Thus, the native libraries must be compiled for each ISA platform on which they are running. For example, a native library written in C and compiled on an Intel Pentium 4 processor (IA-32 instruction set architecture (ISA)) cannot be executed on an Intel Itanium processor family (IPF) ISA. Therefore, if a developer would like to move a managed application or VM from one processor platform to another, they must rewrite and/or recompile any native libraries that are required.
To enable the execution of managed applications that are linked to native libraries that are associated with ISAs different from the ISA of the operating platform, developers have created several strategies. One method utilizes one VM for each ISA with which native libraries are associated. For example, to execute a managed application linked to a 32-bit native library a 32-bit VM is used and to execute a managed application linked to a 64-bit native library a 64-bit VM is used. In such an arrangement, the VM translates the managed application bytecode to the ISA of the emulation layer (which is different than the current platform's ISA). Subsequently, the emulation layer translates the managed application bytecode to the ISA of the current platform. This double translation results in a decrease in performance when executing managed applications and is, thus, undesirable. This approach requires increased complexity due to the multiple required VMs and does not allow managed applications that link to two or more native libraries that are associated with different ISAs to be executed.